import re

from django import forms
from django.db.models import Q
from django.db import transaction
from django.http import JsonResponse
from django.shortcuts import render, redirect
from django.core.validators import ValidationError

from web import models
from utils.encrypt import md5
from utils.pager import Pagination
from utils.link import filter_reverse
from utils.response import BaseResponse
from utils.bootstrap import BootStrapForm
from utils.group import NbSearchGroup, Option


def user_list(request):
    """
    用户列表
    # 客户被删除（逻辑删除），active = 0，以后可以在有以个回收站功能
    # 由于Customer表与Level表有关联，若设置了级联删除那么客户表也会受影响,
    #   - 也可以在删除Level表时设置判断，若有关联数据则不让删除
    #   - 也可以设置默认值
    #   - 啥也不做
    """
    search_group = NbSearchGroup(
        request,
        models.Customer,
        Option('level', db_condition={'active': 1}),  # FK
    )

    # 设置关联查询，level__active=1表示只查询Level表中active=1的数据
    # select_related('level', 'createdBy')
    keyword = request.GET.get('keyword')
    con = Q()
    if keyword:
        keyword = keyword.strip()
        con.connector = 'OR'
        con.children.append(Q(username__contains=keyword))
        con.children.append(Q(mobile__contains=keyword))
        con.children.append(Q(level__title__contains=keyword))

    queryset = models.Customer.objects.filter(con).filter(**search_group.get_condition).filter(active=1).select_related(
        'level', 'createdBy').order_by('id')
    obj = Pagination(request, queryset, 10)
    # for row in queryset:
    #     # 这里设置了对象的__str__方法，所以可以直接打印
    #     print(row.level)
    #     print(row.createdBy)
    #     或人为跨表,但这样每一行数据都会跨一次表，影响性能，不入直接连表查询
    #     print(row.level.title)

    context = {
        'queryset': queryset[obj.start: obj.end],
        'page_string': obj.html,
        'keyword': keyword,
        'search_group': search_group

    }
    return render(request, 'user_list.html', context)


class CustomerModelForm(BootStrapForm, forms.ModelForm):
    exclude_field_list = ['level']
    confirm_password = forms.CharField(label='确认密码', widget=forms.PasswordInput(attrs={'class': 'form-control'}))

    class Meta:
        model = models.Customer
        fields = ['username', 'mobile', 'password', 'confirm_password', 'level']
        widgets = {
            # render_value=True, 保留密码
            'password': forms.PasswordInput(render_value=True, attrs={'class': 'form-control'}),
            'level': forms.RadioSelect(attrs={'class': "form-radio"}),
        }

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # < QuerySet[ < Level: VIP >, < Level: VIP2 >] >
        self.fields['level'].queryset = models.Level.objects.filter(active=1)

    # def clean_mobile(self):
    #     mobile = self.cleaned_data['mobile']
    #     if not re.match(r'^\d{11}$', mobile):
    #         raise forms.ValidationError('手机号格式错误')

    def clean_password(self):
        password = self.cleaned_data['password']
        return md5(password)

    def clean_confirm_password(self):
        password = self.cleaned_data['password']
        confirm_password = self.cleaned_data['confirm_password']
        if password != md5(confirm_password):
            raise ValidationError('密码不一致')
        return confirm_password


def user_add(request):
    """用户添加"""
    if request.method == 'GET':
        form = CustomerModelForm()
        return render(request, 'form2.html', {'form': form})
    form = CustomerModelForm(data=request.POST)
    if not form.is_valid():
        return render(request, 'form2.html', {'form': form})

    form.instance.createdBy_id = request.nb_user.id
    form.save()

    return redirect('user_list')


class CustomerResetModelForm(BootStrapForm, forms.ModelForm):
    confirm_password = forms.CharField(label='确认密码', widget=forms.PasswordInput(attrs={'class': 'form-control'}))

    class Meta:
        model = models.Customer
        fields = ['password']

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

    def clean_password(self):
        password = self.cleaned_data['password']
        return md5(password)

    def clean_confirm_password(self):
        password = self.cleaned_data['password']
        confirm_password = self.cleaned_data['confirm_password']
        if password != md5(confirm_password):
            raise ValidationError('密码不一致')
        return confirm_password


def user_reset(request, pk):
    """用户密码重置"""
    if request.method == 'GET':
        form = CustomerResetModelForm()
        return render(request, 'form2.html', {'form': form})

    instance = models.Customer.objects.filter(id=pk).first()
    form = CustomerResetModelForm(data=request.POST, instance=instance)

    if not form.is_valid():
        return render(request, 'form2.html', {'form': form})

    form.save()
    return redirect('user_list')


class CustomerEditModelForm(BootStrapForm, forms.ModelForm):
    exclude_field_list = ['level']

    class Meta:
        model = models.Customer
        fields = ['username', 'mobile', 'level']
        widgets = {
            # render_value=True, 保留密码
            'level': forms.RadioSelect(attrs={'class': "form-radio"}),
        }

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # < QuerySet[ < Level: VIP >, < Level: VIP2 >] >
        self.fields['level'].queryset = models.Level.objects.filter(active=1)


def user_edit(request, pk):
    """用户编辑"""
    instance = models.Customer.objects.filter(id=pk).first()
    if request.method == 'GET':
        form = CustomerEditModelForm(instance=instance)
        return render(request, 'form2.html', {'form': form})

    form = CustomerEditModelForm(data=request.POST, instance=instance)
    if not form.is_valid():
        return render(request, 'form2.html', {'form': form})
    form.save()

    return redirect(filter_reverse(request, 'user_list'))


def user_delete(request):
    """用户删除"""
    cid = request.GET.get('cid')
    if not cid:
        res = BaseResponse(status=False, detail='参数错误')
        return JsonResponse(res.dict)

    models.Customer.objects.filter(id=cid, active=1).update(active=0)
    res = BaseResponse(status=True)
    return JsonResponse(res.dict)


class ChargeModelForm(BootStrapForm, forms.ModelForm):
    class Meta:
        model = models.TransactionHistory
        fields = ['charge_type', 'price', 'remarks']

    # 这么是静态数据，在程序头一次运行时执行，只适合固定数据，不适合动态数据
    charge_type = forms.TypedChoiceField(
        label="类型",
        choices=[(1, "充值"), (2, "扣款")],  # 只适合固定的数据，不适合去数据表中数据
        coerce=int,
    )

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # 动态数据
        # charge_type = forms.ChoiceField(
        # label='交易类型',
        # choices=((1, '充值'), (2, '扣款')),
        # widget=forms.RadioSelect(attrs={'class': 'form-radio'})
        # )


def user_charge(request, pk):
    """用户交易"""
    queryset = models.TransactionHistory.objects.filter(customer_id=pk, customer__active=1).order_by('-id')
    pager = Pagination(request, queryset)
    form = ChargeModelForm()
    # locals() 函数返回当前局部符号表的字典。这个符号表包含了当前作用域内所有局部变量及其值。
    return render(request, 'user_charge.html', locals())


def user_charge_add(request, pk):
    """创建交易"""
    form = ChargeModelForm(data=request.POST)
    res = BaseResponse()
    if not form.is_valid():
        res.detail = form.errors
        return JsonResponse(res.dict)

    # 由于以下操作为原子性操作（即要成功都成功，要失败都失败），所以使用事务，一旦失败，则全部数据回滚
    try:
        with transaction.atomic():
            # select_for_update加入锁，防止多个用户同时操作。
            cus_object = models.Customer.objects.filter(id=pk, active=1).select_for_update().first()
            charge_type = form.cleaned_data.get('charge_type')
            price = form.cleaned_data.get('price')
            # 更新用户表中的余额
            if charge_type == 1:
                cus_object.balance = cus_object.balance + price
            else:
                # 类型为扣款判断用户余额是否充足
                if cus_object.balance < price:
                    res.detail = {'price': ['余额不足']}
                    return JsonResponse(res.dict)
                cus_object.balance = cus_object.balance - price
            cus_object.save()

            # 添加该用户的交易记录
            form.instance.admin_id = request.nb_user.id
            form.instance.customer_id = pk
            form.save()
    except Exception as e:
        res.detail = {'price': ['操作失败']}
        return JsonResponse(res.dict)
    res.status = True
    return JsonResponse(res.dict)
    # models.TransactionHistory.objects.create(**form.cleaned_data, customer_id=pk)
